package com.sunshine.knn;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;

import com.alibaba.fastjson.util.TypeUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.io.FileUtils;

/**
 * Created by hadoop on 17/10/30.
 */
public class KNN {

    //计算距离
    public double calcDis(List data,double []preData){

        double value = 0;
        for(int i=0;i<preData.length;i++){
            value+=Math.pow(TypeUtils.castToDouble(data.get(i))-preData[i],2);
        }
        return Math.sqrt(value);
    }


    public String predict(List<List> datas, double []preData,int k) {

        int cols = datas.get(0).size();
        //计算记录最近的K个
        Map<Integer, Double> dataIndex = Maps.newHashMap();
        int index = 0;
        for (List data : datas) {
            dataIndex.put(index++, calcDis(data, preData));
        }
        List<Integer> indexs = Lists.newArrayList();
        //获取dis中数值最小的K个数的下标
        List<Map.Entry<Integer, Double>> list = new ArrayList<Entry<Integer, Double>>();
        list.addAll(dataIndex.entrySet());
        Collections.sort(list, new ValueComparator());//按照value排序
        for (int i = 0; i < k; i++) {
            indexs.add(list.get(i).getKey());
        }

        //k个里面出现次数最多的label
        Map<String, AtomicInteger> results = Maps.newHashMap();
        for (Integer integer : indexs) {
            String label = (String)datas.get(integer).get(cols - 1);
            if (results.containsKey(label)) {
                results.get(label).incrementAndGet();
            } else {
                results.put(label, new AtomicInteger(1));
            }
        }
        String resultLabel = null;
        int maxValue = -1;
        //返回出现次数最多的label
        for (Map.Entry<String, AtomicInteger> entry : results.entrySet()) {
            if (entry.getValue().get() > maxValue) {
                resultLabel = entry.getKey();
                maxValue = entry.getValue().get();
            }

        }
        return resultLabel;
    }



    public static void main(String [] args) throws IOException {
        KNN knn = new KNN();
        List<String> lines = FileUtils.readLines(new File("src/main/resources/iris.dat"), "utf-8");

        List<List> datas = Lists.newArrayList();
        for (String line : lines) {
            datas.add(Lists.newArrayList(line.split(",")));
        }

        double[] preData = {0.3,3.9,6.6,0.8};

        System.out.println(knn.predict(datas, preData,10));

    }

    private static class ValueComparator implements Comparator<Map.Entry<Integer,Double>>
    {
        public int compare(Map.Entry<Integer,Double> m,Map.Entry<Integer,Double> n)
        {
            return m.getValue().compareTo(n.getValue());
        }
    }

}
